package gui;

import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.*;

import javax.swing.*;

import netcode.helper.NetcodeHelper;
import netcode.helper.ClientMessageListener;
import netcode.client.Client;

import gamePlay.*;


public class MenuCycling implements ClientMessageListener {
//public class MenuCycling {
    static JFrame frame = new JFrame();    // frame for GUI displays
    static StartingMenu startScreen;
    static LobbySelectionMenu lobbySelectScreen;
    static LobbyMenu lobbyScreen;
    static JoinLobbyMenu joinLobbyScreen;
    static Game g;
    static Client client;
    public static boolean serverLobbyInfoReceived = false;
	public static boolean gameLobbyInfoReceived = false;
	public static boolean questionReceived = false;
	public static boolean bettingOddsReceived = false;
	public static boolean roundResultsReceived = false;
	public static boolean endOfGameReceived = false;
    //static Player p1;
//    static Player p2;
//    static Player p3;
//    static Player p4;
//    static Player p5;
//    static Player p6;
    //static ArrayList<Integer> displayAnswers;
    //static ArrayList<Integer> sortedAnswers = new ArrayList<Integer>();
    //static ArrayList <Integer> odds = new ArrayList<Integer>();
    //static ArrayList <Integer> payouts = new ArrayList<Integer>();
    //static int num_Players;
    static int round = 0;
   
    
    //static LobbySelectionMenu lobbySelectionScreen;
    //static LobbyMenu hostLobbyScreen;
    static int screenSize = 2;
    public static void main (String[] args)
    {
        Toolkit toolkit = Toolkit.getDefaultToolkit();
        Dimension dim = toolkit.getScreenSize();
       // for testing
       // System.out.println("width = " + dim.width + "   height = " + dim.height);
        if (dim.width < 1440 || dim.height < 900 )
        	screenSize = 1;
        
        //startScreen = new StartingMenu(screenSize);
        
        lobbySelectScreen = new LobbySelectionMenu(screenSize);
        lobbyScreen = new LobbyMenu(screenSize);
        joinLobbyScreen = new JoinLobbyMenu(screenSize);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//        frame.add(startScreen);
//        frame.pack();
//        frame.repaint();
//        frame.setVisible(true);        
       // lobbySelectionScreen = new LobbySelectionMenu();
        //hostLobbyScreen = new LobbyMenu();
        MenuCycling test = new MenuCycling();
        test.startGameMulti();
    }
    
    public void startGameMulti(){
    	g = new Game();
    	String name = JOptionPane.showInputDialog("Enter your name.");
		Player p1 = new Player(name);
		try{
		client = new Client(NetcodeHelper.SERVER_ADDRESS,
				NetcodeHelper.SERVER_PORT, name, g);
		client.setListener(this);
		client.start();
		client.sendConnectionRequest();
		int option = 0;
		do {
				displayMainMenu();
				System.out.print("Please enter your choice:");
				option = Integer.parseInt(JOptionPane.showInputDialog("Enter option."));
				switch (option) {
				case 1:
					printServerLobby();
					break;
				case 2:
					createGame();
					break;
				case 3:
					joinGame();
					break;
				case 4:
					disconnect();
					break;
				}
			} while (option != 4);
		} catch (Exception e) {
			System.err.println(e);
		}
			
    }
    
    
    // initializes the game state
    public static void startGame(int num_play){
    	
    	int num_Players = num_play;
    	//integration testing
    	g = new Game("Good Team", num_Players);
    	String name = JOptionPane.showInputDialog("Enter your name.");
		Player p1 = new Player(name);
	        p1.joinGame(g);
	    for(int i = 1; i < num_Players; i++){
	    	ComputerPlayer comp = new ComputerPlayer("Computer " + i + "");
	    	comp.joinGame(g);
	    }
	       
//		if (num_Players >= 3){
//			p2 = new ComputerPlayer("CPU 1");
//			p2.joinGame(g);
//			p3 = new ComputerPlayer("CPU 2");
//			p3.joinGame(g);
//			if (num_Players >= 4){
//				p4 = new ComputerPlayer("CPU 3");
//				p4.joinGame(g);
//					if(num_Players >= 5){
//						p5 = new ComputerPlayer("CPU 4");
//						p5.joinGame(g);
//						if (num_Players == 6){
//							p6 = new ComputerPlayer("CPU 5");
//							p6.joinGame(g);
//						}
//					}
//			}
//		}
//        betScreen = new BetMenu(screenSize);
//        betTimer = new javax.swing.Timer(1000, betScreen.new TimerListener());
//        resultScreen = new ResultsMenu();
//        resultTimer = new javax.swing.Timer(1000, resultScreen.new TimerListener());
//        winScreen = new WinMenu(screenSize);
//        winTimer = new javax.swing.Timer(1000, winScreen.new TimerListener());
		g.createMenus(screenSize);
        displayQuestionScreen();
	}	
    
    // returns the current question
    public static String getQuestion(){
    	return g.getQuestionGUI();
    }
    
    // returns the correct answer
    public static int getAnswer(){
    	return g.getAnswer();
    }
    
    //returns the Chip count of the Player
//    public static int getPlayerChips(){
//    	return p1.getGame_chips() + p1.getPermanent_chips();    	
//    }
    
    // submit the guesses of all players. Currently uses a static guess for each player except the user
    public static void guess(Integer playerGuess){
    	g.getPlayers().get(0).submitGuess(playerGuess);
    	for (int i = 1; i < g.getPlayers().size(); i++) {
			ComputerPlayer comp = ((ComputerPlayer) (g.getPlayers().get(i)));
			comp.submitGuess(g.getQuestion().getAnswer());
		}
//    	if (num_Players >= 3){
//    		p2.submitGuess(g.getQuestion().getAnswer());
//        	p3.submitGuess(g.getQuestion().getAnswer());
//			if (num_Players >= 4){
//				p4.submitGuess(g.getQuestion().getAnswer());
//					if(num_Players >= 5){
//						p5.submitGuess(g.getQuestion().getAnswer());
//						if (num_Players == 6){
//							p6.submitGuess(g.getQuestion().getAnswer());
//						}
//					}
//			}
//		}		
// TODO make sure this isn't fucked
//		displayAnswers = g.answers();
    }
    
     // return the best answer of all answers submitted.
    public static int getBest(){
    
    	int answer = g.getAnswer();
    	ArrayList<Guess> guesses = (ArrayList<Guess>) g.getGuesses();
		Guess winner = guesses.get(0);
		int win_location = 0;
		// The for loop below determines which guess was closest to the answer
		for (int i = 0; i < guesses.size(); i++) {
			int difference = Math.abs(answer - guesses.get(i).getGuess());
			if (difference < (Math.abs(answer - winner.getGuess()))) {
				winner = guesses.get(i);
				win_location = i;
			}
		}
		return winner.getGuess();
    	// TODO messed with this still, confirm working
//    	int correct = getAnswer();
//       
//    	for(int i = sortedAnswers.size() - 1;i >=0;i--)
//    		if(sortedAnswers.get(i) <= correct)
//    			return sortedAnswers.get(i);
//    	return 0;
//    	
    }
    
     public static void updateQuestions(){
    	g.updateQuestions();
    }

    //method for calculating the odds on each bet is tiered
   // TODO make this obsolete
//     public static void oddsCalc(){
//        sortedAnswers.clear();
// 
//        int total=0;
////    	ArrayList<Integer> sortedAnswers = new ArrayList<Integer>();
//    	for(int x= 0; x< displayAnswers.size(); x++)
//    	{
//    		total += displayAnswers.get(x);
//    		sortedAnswers.add(displayAnswers.get(x));
//    	}
//    	
////    	for(int i = 0; i < sortedAnswers.size(); i++)
////    		System.out.println(sortedAnswers.get(i));
//    	
//    	//ArrayList <Integer> odds = new ArrayList<Integer>();
//    	//odds.add(total/sortedAnswers.get(0));
//    	//odds.add(total/sortedAnswers.get(1));
//    	odds.add(2);
//    	odds.add(2);
//    	if (displayAnswers.size()>4)
//    	{
//    		odds.add(2);
//    		//odds.add(total/sortedAnswers.get(2));
//    	}
////    	return 0;
//    	
//    	
//    }
    

    
    public static void displayStartScreen(){

/*
 * The following 2 lines were creating a null pointer exception when the user was returning from the select game lobby
 * back to the start screen.    	
 */
//    	g.winTimer.stop();
//    	g.winScreen.seconds = 60;        
        frame.getContentPane().removeAll();
        round = 0;
        // update the frame
        frame.add(startScreen);
        frame.validate();
        frame.pack();
        frame.repaint();
        frame.setVisible(true);
    }
    
    
     // This method will change the frame to display the Question panel
    public static void displayQuestionScreen() {
        
    	//g.resultTimer.stop();
    	//g.resultScreen.seconds = 60;
        frame.getContentPane().removeAll();
        round++;
        // update the frame
        //g.updateQuestions();
        g.questScreen.setQuestion();
        g.questScreen.clearFields();
        //g.questTimer.start();
        frame.add(g.questScreen);
        frame.validate();
        frame.pack();
        frame.repaint();
        frame.setVisible(true);

    }   
    
    
public static void displayBetScreen(){
        g.questTimer.stop();
        g.questScreen.seconds = 30;
        g.betScreen.refreshAnswers();
        g.betScreen.setChips();
                
        frame.remove(g.questScreen);
        g.betTimer.start();
        // update the frame
        frame.add(g.betScreen);
        frame.validate();
        frame.pack();
        frame.repaint();
        frame.setVisible(true);
    }
    
    public static void displayResultScreen(){
       
    	//MenuCycling.p1.setPermanent_chips(2);
    	
        frame.remove(g.betScreen);
        g.betTimer.stop();
        g.betScreen.seconds = 30;
        
        // update the frame
        if (round == 7){
        	g.winScreen.setText();
        	g.winTimer.start();
        	g.winScreen.refreshAnswers();
        	frame.add(g.winScreen);
        }
        else{
        	g.resultScreen.setText();
        	g.resultTimer.start();
        	g.resultScreen.refreshAnswers();
        	frame.add(g.resultScreen);
        }
        frame.validate();
        frame.pack();
        frame.repaint();
        frame.setVisible(true);
    }
    
    public static void displaySelectLobbyScreen(){
    	 frame.getContentPane().removeAll();
        // update the frame
        frame.add(lobbySelectScreen);
        frame.validate();
        frame.pack();
        frame.repaint();
        frame.setVisible(true);
    }
    
    public static void displayLobbyScreen(){
        frame.remove(lobbySelectScreen);
        // update the frame
        frame.add(lobbyScreen);
        frame.validate();
        frame.pack();
        frame.repaint();
        frame.setVisible(true);
    }
    
    public static void displayJoinLobbyScreen(){
        frame.remove(lobbySelectScreen);
        // update the frame
        frame.add(joinLobbyScreen);
        frame.validate();
        frame.pack();
        frame.repaint();
        frame.setVisible(true);
    }

	@Override
	public void onMessageReceived(byte packetCode) {
		System.out.println("onMessageReceived() entered with code: " + packetCode);
		switch (packetCode) {
		case NetcodeHelper.SERVER_LOBBY_INFO_RESPONSE:
			serverLobbyInfoReceived = true;
			break;
		case NetcodeHelper.GAME_LOBBY_INFO:
			gameLobbyInfoReceived = true;
			break;
		case NetcodeHelper.QUESTION:
			questionReceived = true;
			break;
		case NetcodeHelper.BETTING_ODDS:
			bettingOddsReceived = true;
			break;
		case NetcodeHelper.ROUND_RESULTS:
			roundResultsReceived = true;
			break;
		case NetcodeHelper.GAME_RESULTS:
			endOfGameReceived = true;
			break;
		}
	}
	
	public void printServerLobby() {
		serverLobbyInfoReceived = false;
		do {
			client.sendServerLobbyInfoRequest();
			sleepyTime();
		} while (!serverLobbyInfoReceived);
		
		// Clean this up once Lobby is fully implemented
		System.out.println(client.getLobby());
		JOptionPane.showMessageDialog(null, client.getLobby());

	}

	public void createGame() {
		Scanner keyboard = new Scanner(System.in);
		System.out.print("Please input a game name: ");
		//String name = keyboard.nextLine();
		String name = JOptionPane.showInputDialog(null, "Please input a game name: ");
		client.sendCreateGameRequest(name, 7, new String[] {});
		hostGameLobby();
	}

	public void joinGame() {
		Scanner keyboard = new Scanner(System.in);
		System.out.print("Please input the gameId: ");
		int gameId = Integer.parseInt(JOptionPane.showInputDialog("Please input the gameId"));
		//int gameId = keyboard.nextInt();
		gameLobbyInfoReceived = false;
		do {
			client.sendJoinGameRequest(gameId);
			sleepyTime();
		} while (!gameLobbyInfoReceived);
		clientGameLobby();
	}

	public String getNameFromUser() {
		Scanner keyboard = new Scanner(System.in);
		System.out.print("Please input your name: ");
		String name = keyboard.nextLine();
		return name;
	}

	public void displayMainMenu() {
		JOptionPane.showMessageDialog(null, "Main Menu \n 1. Print Server Lobby \n 2. Create Game \n 3. Join Game \n 4. Quit");
		System.out.println("*******Main Menu*******");
		System.out.println("1. Print Server Lobby");
		System.out.println("2. Create Game");
		System.out.println("3. Join Game");
		System.out.println("4. Quit");
	}

	public void displayHostGameMenu() {
		JOptionPane.showMessageDialog(null, "Game Menu \n 1. Print Game Lobby \n 2. Start Game \n 3. Leave Game");
		System.out.println("*******Game Menu*******");
		System.out.println("1. Print Game Lobby");
		System.out.println("2. Start Game");
		System.out.println("3. Leave Game");
	}
	
	public void displayClientGameMenu(){
		JOptionPane.showMessageDialog(null, "Game Menu \n 1. Print Game Lobby \n 2. Wait for Game to Start \n 3. Leave Game");
		System.out.println("*******Game Menu*******");
		System.out.println("1. Print Game Lobby");
		System.out.println("2. Wait for Game to Start");
		System.out.println("3. Leave Game");
	}

	public void hostGameLobby() {
		int option = 0;
		Scanner keyboard = new Scanner(System.in);
		do {
			displayHostGameMenu();
			
			//JOptionPane.showMessageDialog(null, "Please input your selection: ");
			System.out.print("Please input your selection: ");
			//option = Integer.parseInt(JOptionPane.showInputDialog("Please input your selection: "));
			//option = keyboard.nextInt();
			option = Integer.parseInt(JOptionPane.showInputDialog("Please input your seletion: "));
			switch (option) {
			case 1:
				printGameLobby();
				break;
			case 2:
				hostStartGame();
				break;
			case 3:
				leaveGame();
				break;
			}
		} while (option != 3);
	}
	
	public void clientGameLobby(){
		int option = 0;
		Scanner keyboard = new Scanner(System.in);
		do {
			displayClientGameMenu();
			System.out.print("Please input your selection: ");
			option = keyboard.nextInt();
			switch (option) {
			case 1:
				printGameLobby();
				break;
			case 2:
				clientStartGame();
				break;
			case 3:
				leaveGame();
				break;
			}
		} while (option != 3);
	}

	public void disconnect() {
		client.sendDisconnect();
	}

	public void leaveGame() {
		client.sendLeaveGameRequest(g.getGameID());
	}

	public void hostStartGame(){
		questionReceived = false;
		do {
			client.sendStartGameRequest(g.getGameID());
			sleepyTime();
		} while (!questionReceived);
		startGame();
	}
	
	public void clientStartGame(){
		do {
			sleepyTime();
		} while (!questionReceived);
		startGame();
	}
	
	public void startGame() {
		questionReceived = false;
		g.createMenus(screenSize);
		displayQuestionScreen();
//		Scanner keyboard = new Scanner(System.in);
//		int choice = 0;
//		
//		//questionReceived = false;
//		do {
//			questionReceived = false;
//			System.out.println(g.getQuestion().getText());
//			//game.displayQuestion();
//			System.out.print("Please Input your answer: ");
//			int answer = keyboard.nextInt();
//			client.sendAnswer(g.getGameID(), answer);
//			System.out.println("Waiting for other players...");
//			do {
//				sleepyTime();
//			} while (!bettingOddsReceived);
//			bettingOddsReceived = false;
//			List<Guess> guesses = g.getGuesses();
//			System.out.println("***Guesses and Odds***");
//			for(int i = 0; i < guesses.size(); i++){
//				System.out.println("Guess " + i + ": " + guesses.get(i).getGuess() + " Odds: " + guesses.get(i).getOdds());
//			}
//			List<Bet> bets = getPlayerBets(g.getGuesses());
//	System.out.println(bets);
//			client.sendSubmitBets(bets, g.getGameID());
//			System.out.println("Waiting for other players...");
//			do {
//				sleepyTime();
//			} while (!roundResultsReceived);
//			roundResultsReceived = false;
//			System.out
//					.println("***Round Results***");
//			System.out.println("The correct answer was: " + g.getQuestion().getAnswer());
//			for(int i = 0; i < g.getPlayers().size(); i++){
//				System.out.println(g.getPlayers().get(i).getPlayer_name() + " now has " + g.getPlayers().get(i).getGame_chips() + " game chips.");
//			}
//
//			do {
//				System.out.println("1. Continue to the next round");
//				System.out.println("2. Leave Game");
//				System.out.print("Please enter your selection: ");
//				choice = keyboard.nextInt();
//			} while (choice < 1 || choice > 2);
//			if (choice == 1) {
//				client.sendNextRoundRequest(g.getGameID());
//			} else if (choice == 2) {
//				leaveGame();
//				break;
//			}
//			do {
//				sleepyTime();
//			} while (!questionReceived && !endOfGameReceived);
//		} while (!endOfGameReceived);
//		endOfGameReceived = false;
//		System.out.println("Print the end of game results here!");

	}

	public void printGameLobby() {
		String players = "";
		for (int i = 0; i < g.getPlayers().size(); i++) {
			System.out.println("*****Players*****");
			System.out.println(g.getPlayers().get(i).getPlayer_name());
			players = players + "\n" + g.getPlayers().get(i).getPlayer_name();
		}
		JOptionPane.showMessageDialog(null, "Players" + players);
	}

	private List<Bet> getPlayerBets(List<Guess> guesses) {
		Scanner keyboard = new Scanner(System.in);
		List<Bet> bets = new ArrayList<Bet>();
		int choice = -1;
		int permaChips = 0;
		int tempChips = 0;
		System.out.println("Place your bets now.");
		do {
			System.out
					.print("On which guess do you wish to place a bet(-1 to end betting): ");
			choice = keyboard.nextInt();
			if (choice >= 0 && choice < guesses.size()) {
				System.out
						.print("How many permanent chips would you like to bet: ");
				permaChips = keyboard.nextInt();
				System.out
						.print("How many temporary chips would you like to bet: ");
				tempChips = keyboard.nextInt();
				/* Changed to work with new bet format - Jim J */
				bets.add(new Bet(g.getPlayers().get(0).getPlayer_name(), choice, permaChips, tempChips));
			}
		} while (choice != -1);
		System.out.println();
		return bets;
	}
	
	public static void sleepyTime() {
		try {
			Thread.sleep(NetcodeHelper.MILLISECONDS_BETWEEN_SENDING_MESSAGE);
		} catch (Exception e) {
			System.err.println(e);
		}
	}
}